package org.ponly.uno4j.support;

import org.ponly.common.util.FileUtils;
import org.ponly.uno4j.core.UnoClient;
import org.ponly.uno4j.core.UnoTask;
import org.ponly.uno4j.util.PdfUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.util.concurrent.*;

/**
 * PDF - SWF 转换服务
 *
 * @author vacoor
 */
public abstract class D2sService extends D2sSupport {
    private static final Logger LOG = LoggerFactory.getLogger(D2sService.class);

    private UnoClient unoClient;
    private int maxWorks;
    private BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>();
    private ExecutorService taskExecutorService;
    private TaskListener taskListener;

    public D2sService(UnoClient unoClient, int maxWorks) {
        this.unoClient = unoClient;
        this.maxWorks = maxWorks;
        this.taskExecutorService = new ThreadPoolExecutor(maxWorks, maxWorks, 0, TimeUnit.MINUTES, workQueue);
    }

    public void submit(final D2sTask task) {
        // id = save(id, name, filename, size)
        // create(path + id)
        // hash
        //
        addTask(task);
        runNextTask();
    }

    /**
     * 如果
     */
    protected void runNextTask() {
        if (workQueue.size() < maxWorks) {
            final D2sTask nextTask = acquireTask();
            if (null != nextTask) {
                taskExecutorService.submit(newWorkerFor(nextTask));
            }
        }
    }

    private Runnable newWorkerFor(final D2sTask task) {
        return new Runnable() {
            @Override
            public void run() {
                Exception taskException = null;
                try {
                    if (LOG.isInfoEnabled()) {
                        LOG.info("taskToBeExecuted: {}", task);
                    }

                    if (null != taskListener) {
                        taskListener.taskToBeExecuted(task);
                    }

                    String source = task.getSource();
                    String pdf = source;
                    String swf = task.getSwf();
                    String extension = FileUtils.getExtension(source, false);

                    // 文档 -> pdf -> swf 任务
                    // submit(source, swf).get();

                    // 如果不是 pdf
                    if (!PDF.equalsIgnoreCase(extension)) {
                        pdf = pdf + PDF_SUFFIX;
                        UnoTask pdfTask = makeDocToPdfTask(source, pdf);
                        Future<?> future = getUnoClient().submit(pdfTask);
                        future.get();
                    }

                    task.setPdf(pdf);
                    try {
                        int pages = PdfUtils.getNumberOfPages(new File(pdf));
                        swf = swf.replace("?-%", pages + "-%");
                        task.setSwf(swf);
                    } catch (IOException ignore) {
                        // ignore
                    }

                    // pdf -> swf 转换任务
                    FutureTask<?> swfTask = makePdfToSwfTask(source, swf);
                    doExecutePdfToSwfTask(swfTask);

                    swfTask.get();
                } catch (Exception ex) {
                    taskException = ex;
                } finally {
                    try {
                        if (LOG.isInfoEnabled()) {
                            LOG.info("taskWasExecuted: {}, executionException: {}", task, taskException);
                        }
                        if (null != taskListener) {
                            taskListener.taskWasExecuted(task, taskException);
                        }
                    } catch (Exception ignore) {
                        // ignore
                    }
                    runNextTask();
                }
            }
        };
    }

    /**
     * 添加任务到任务队列
     *
     * @param task 待添加的任务
     */
    protected abstract void addTask(D2sTask task);

    /**
     * 从任务队列中获取一个任务
     *
     * @return 任务
     */
    protected abstract D2sTask acquireTask();

    /**
     * {@inheritDoc}
     */
    @Override
    protected UnoClient getUnoClient() {
        return unoClient;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void doExecutePdfToSwfTask(FutureTask<?> pdfToSwfTask) {
        pdfToSwfTask.run();
    }

    public TaskListener getTaskListener() {
        return taskListener;
    }

    public void setTaskListener(TaskListener taskListener) {
        this.taskListener = taskListener;
    }

    public void shutdown() {
        taskExecutorService.shutdown();
        try {
            taskExecutorService.awaitTermination(30, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            // ignore
        }
        if(!taskExecutorService.isTerminated()) {
            taskExecutorService.shutdownNow();
        }
        getUnoClient().shutdown();
    }
}
